﻿// owner 蒋家伟

#include "SocketWorker.h"

// qt
#include <QString>
#include <QHostAddress>
#include <QTime>

// jsdk
#include "StringUtils.h"
#include "Dbg_Warn_Define.h"

using namespace jsdk;

OwnerPtr<SocketWorker> jsdk::SocketWorker::create(ISocketEventHandler * pSocketEventHandler)
{
    OwnerPtr<SocketWorker> opSocketWorker = NEW_AS_OWNERPTR(SocketWorker);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opSocketWorker, L"SocketWork创建失败", L"蒋家伟", L"2023-07-27");
    opSocketWorker->m_wpSocketEventHandler = pSocketEventHandler;
    return std::move(opSocketWorker);
}

void jsdk::SocketWorker::TcpSocketDeleter::operator()(QTcpSocket* pSocket)
{
    if (pSocket)
    {
        pSocket->deleteLater();
    }
}

bool jsdk::SocketWorker::isOnLine() const
{
    return m_opTcpSocket != nullptr && m_opTcpSocket->isValid();
}

void jsdk::SocketWorker::onReadyRead()
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_opTcpSocket, L"套接字还没有创建, ip:" + m_ipStr + L" port : " + m_portStr, L"蒋家伟", L"2023-07-26");
    if (m_wpSocketEventHandler)
    {
        m_wpSocketEventHandler->recvMessage(m_opTcpSocket->readAll());
    }
    return;
}

void jsdk::SocketWorker::onSend(QByteArray msg, qint64 length)
{
    DBG_WARN_UNLESS(m_opTcpSocket, L"套接字还没有创建, ip:" + m_ipStr + L" port : " + m_portStr, L"蒋家伟", L"2023-07-26");
    if (m_opTcpSocket)
    {
        qint64 sendedbyte = 0;
        QTime startTime;
        startTime.start();
        const char* pStream = msg.constData();
        while (sendedbyte < length && startTime.elapsed() < 2000)
        {
            sendedbyte += m_opTcpSocket->write(pStream + sendedbyte, length - sendedbyte);
        }

        if (m_wpSocketEventHandler)
        {
            m_wpSocketEventHandler->sendMessageFeedback(sendedbyte == length);
        }
    }
    else
    {
        if (m_wpSocketEventHandler)
        {
            m_wpSocketEventHandler->sendMessageFeedback(false);
        }
    }
}

void jsdk::SocketWorker::onConnect(QString ip, qint64 port)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(!m_opTcpSocket, L"当前套接字已经链接，请勿多次触发", L"蒋家伟", L"2023-07-26");
    m_ipStr = ip.toStdWString();
    m_portStr = StringUtils::toWString(port);
    m_opTempTcpSocket.swap(NEW_AS_OWNERPTR_WITH_DELETER(QTcpSocket, jsdk::SocketWorker::TcpSocketDeleter));
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_opTempTcpSocket, L"套接字创建失败，目标Ip为:" + m_ipStr + L" 目标port为: " + m_portStr, L"蒋家伟", L"2023-07-26");

    // 信号与槽连接
    bool success = init();
    DBG_WARN_AND_RETURN_VOID_UNLESS(success, L"Work的信号与槽连接失败, ip:" + m_ipStr + L" port:" + m_portStr, L"蒋家伟", L"2023-07-26");

    m_opTempTcpSocket->connectToHost(QHostAddress(ip), port);

    // todo 是需要考虑等待时间
    //if (!m_upTcpSocket->waitForConnected(5000))
    //{
    //    m_upTcpSocket.reset();
    //}
}

void jsdk::SocketWorker::onError(QAbstractSocket::SocketError socketError)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_opTcpSocket, L"套接字还没有创建, ip:" + m_ipStr + L" port : " + m_portStr, L"蒋家伟", L"2023-07-26");
    m_opTcpSocket->reset();
    if (m_wpSocketEventHandler)
    {
        m_wpSocketEventHandler->socketError(socketError);
    }
}

void jsdk::SocketWorker::onDisConnected()
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_opTcpSocket, L"套接字为空，不应该断开连接, ip:" + m_ipStr + L" port:" + m_portStr, L"蒋家伟", L"2023-09-06");
    m_opTcpSocket.reset();
    if (m_wpSocketEventHandler)
    {
        m_wpSocketEventHandler->disconnect();
    }
}

void jsdk::SocketWorker::onConnected()
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_opTempTcpSocket, L"套接字没有连接成功，不应该发送此信号, ip:" + m_ipStr + L" port : " + m_portStr, L"蒋家伟", L"2023-09-06");
    m_opTcpSocket.swap(m_opTempTcpSocket);
    if (m_wpSocketEventHandler)
    {
        m_wpSocketEventHandler->connectSuccess();
    }
}

bool jsdk::SocketWorker::init() const
{
    // 信号与槽连接
    bool success = connect(m_opTempTcpSocket.get(), &QTcpSocket::connected, this, &jsdk::SocketWorker::onConnected);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(success, L"socket新连接的信号与槽连接失败", L"蒋家伟", L"2023-07-26");

    success = connect(m_opTempTcpSocket.get(), &QTcpSocket::disconnected, this, &jsdk::SocketWorker::onDisConnected);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(success, L"socket断开连接的信号与槽连接失败", L"蒋家伟", L"2023-07-26");

    success = connect(m_opTempTcpSocket.get(), &QTcpSocket::readyRead, this, &jsdk::SocketWorker::onReadyRead);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(success, L"socket等待读取的信号与槽连接失败", L"蒋家伟", L"2023-07-26");

    success = connect(m_opTempTcpSocket.get(), SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(success, L"socket错误信号与槽连接失败", L"蒋家伟", L"2023-07-26");
    return success;
}